/* 
 * Copyright (C) 2001-2003 Jacek Sieka, j_s@telia.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#if !defined(AFX_CHILDFRM_H__A7078724_FD85_4F39_8463_5A08A5F45E33__INCLUDED_)
#define AFX_CHILDFRM_H__A7078724_FD85_4F39_8463_5A08A5F45E33__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include "FlatTabCtrl.h"
#include "TypedListViewCtrl.h"

#include "../client/Client.h"
#include "../client/User.h"
#include "../client/ClientManager.h"
#include "../client/TimerManager.h"
#include "../client/FastAlloc.h"
#include "../client/QueueManager.h"
//Sulan start svn 44
#include "../client/ClientVersionManager.h"
//End
#include "../client/RegexpHandler.h"
#include "WinUtil.h"
#include "UCHandler.h"

#define EDIT_MESSAGE_MAP 10		// This could be any number, really...
// CDM EXTENSION BEGINS (fulDC)
#define FILTER_MESSAGE_MAP 8
// CDM EXTENSION ENDS
// pothead extension starts #13 svn50
#define CLEAR_MESSAGE_MAP 19
// pothead extension ends
// R2 extension begins svn142
#define RESOLVE_IP WM_APP+1
// R2 extension ends svn142
struct CompareItems;

class HubFrame : public MDITabChildWindowImpl<HubFrame>, private ClientListener, 
	public CSplitterImpl<HubFrame>, private TimerManagerListener, public UCHandler<HubFrame>,
	public UserInfoBaseHandler<HubFrame>
	//Sulan start svn 44
	, private VersionManagerListener
	//Sulan start svn124
	, private SettingsManagerListener
	//End
{
public:
	DECLARE_FRAME_WND_CLASS_EX(_T("HubFrame"), IDR_HUB, 0, COLOR_3DFACE);

	typedef CSplitterImpl<HubFrame> splitBase;
	typedef MDITabChildWindowImpl<HubFrame> baseClass;
	typedef UCHandler<HubFrame> ucBase;
	typedef UserInfoBaseHandler<HubFrame> uibBase;

	BEGIN_MSG_MAP(HubFrame)
		NOTIFY_HANDLER(IDC_USERS, LVN_GETDISPINFO, ctrlUsers.onGetDispInfo)
		NOTIFY_HANDLER(IDC_USERS, LVN_COLUMNCLICK, ctrlUsers.onColumnClick)
		NOTIFY_HANDLER(IDC_USERS, LVN_GETINFOTIP, ctrlUsers.onInfoTip)
		NOTIFY_HANDLER(IDC_USERS, NM_DBLCLK, onDoubleClickUsers)
		NOTIFY_HANDLER(IDC_USERS, LVN_KEYDOWN, onKeyDownUsers)
		NOTIFY_HANDLER(IDC_USERS, NM_RETURN, onEnterUsers)
		NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, onGetToolTip)
		MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, onSizeMove)
		MESSAGE_HANDLER(WM_CLOSE, onClose)
		MESSAGE_HANDLER(WM_SETFOCUS, onSetFocus)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_SPEAKER, onSpeaker)
		MESSAGE_HANDLER(WM_CONTEXTMENU, onContextMenu)
		MESSAGE_HANDLER(WM_CTLCOLORSTATIC, onCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLOREDIT, onCtlColor)
		MESSAGE_HANDLER(FTM_CONTEXTMENU, onTabContextMenu)
		// R2 extension begins svn142
		MESSAGE_HANDLER(RESOLVE_IP, onResolvedIP)
		// R2 extendion ends svn142
		COMMAND_ID_HANDLER(ID_FILE_RECONNECT, OnFileReconnect)
		COMMAND_ID_HANDLER(IDC_REFRESH, onRefresh)
		COMMAND_ID_HANDLER(IDC_FOLLOW, onFollow)
		COMMAND_ID_HANDLER(IDC_SEND_MESSAGE, onSendMessage)
		COMMAND_ID_HANDLER(IDC_ADD_AS_FAVORITE, onAddAsFavorite)
		COMMAND_RANGE_HANDLER(IDC_MULTI_COPY, IDC_MULTI_COPY + HubFrame::COLUMN_LAST - 1, onMultiCopy)
		// CDM EXTENSION BEGINS
		COMMAND_ID_HANDLER(IDC_GET_USER_RESPONSES, onGetUserResponses)
		COMMAND_ID_HANDLER(IDC_GET_O_NICK_USER_RESPONSES, onGetoNickUserResponses)
		COMMAND_ID_HANDLER(IDC_GET_R_NICK_USER_RESPONSES, onGetrNickUserResponses)
		COMMAND_ID_HANDLER(IDC_REPORT, onReport)
		COMMAND_ID_HANDLER(IDC_CHECK_FILE_LIST, onCheckFileList)
		COMMAND_ID_HANDLER(IDC_GET_CHECK_FILE_LIST, onGetCheckFileList)
		COMMAND_ID_HANDLER(IDC_RIPE_LOOKUP, onRipeLookup)
// R2 extension begins svn142, 143
		COMMAND_ID_HANDLER(IDC_RESOLVE_IP, onIpLookup)
		COMMAND_ID_HANDLER(IDC_RESOLVE_IP_MAIN, onIpLookup)
// R2 extension ends svn142, 143
		COMMAND_ID_HANDLER(IDC_HUBLIST_LOOKUP, onHublistLookup)
		COMMAND_ID_HANDLER(IDC_CHECK_HUB_COUNTS, onCheckHubCounts)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_KICK, onMultiHubKick)
		COMMAND_ID_HANDLER(IDC_CLEAN_USER, onCleanUser)
		NOTIFY_HANDLER(IDC_USERS, NM_CUSTOMDRAW, onCustomDraw) // from iDC++
		COMMAND_ID_HANDLER(ID_WINAMP_SPAM, onWinampSpam)
		COMMAND_ID_HANDLER(ID_SWITCH, onSwitch)
		// CDM EXTENSION ENDS
		COMMAND_ID_HANDLER(IDC_CLOSE_WINDOW, onCloseWindow)
		COMMAND_ID_HANDLER(ID_EDIT_COPY, onEditCopy)
		COMMAND_ID_HANDLER(ID_EDIT_FIND, onEditFind)
		// Pothead extension Starts #3, svn61, svn62
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW1, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW2, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW3, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW4, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW5, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW6, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW7, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW8, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW9, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_MULTI_HUB_RAW10, onMultiHubRaw)
		COMMAND_ID_HANDLER(IDC_OPEN_HUB_LOG, onOpenHubLog)
		COMMAND_ID_HANDLER(IDC_GLOBAL_BAN, onMainBan)
		COMMAND_ID_HANDLER(IDC_HUB_BAN, onMainBan)
		COMMAND_ID_HANDLER(IDC_COPY_HUB_ADDRESS, onCopyHubAddy)
		// Pothead extension ends
		//Sulan start 144
		COMMAND_ID_HANDLER(IDC_START_CHECKING, onStartChecking)
		//End
		CHAIN_COMMANDS(ucBase)
		CHAIN_COMMANDS(uibBase)
		CHAIN_MSG_MAP(baseClass)
		CHAIN_MSG_MAP(splitBase)
	ALT_MSG_MAP(EDIT_MESSAGE_MAP)
		MESSAGE_HANDLER(WM_CHAR, onChar)
		MESSAGE_HANDLER(WM_KEYDOWN, onChar)
		MESSAGE_HANDLER(WM_KEYUP, onChar)
		MESSAGE_HANDLER(BM_SETCHECK, onShowUsers)
		MESSAGE_HANDLER(WM_LBUTTONDBLCLK, onLButton)
		MESSAGE_HANDLER(WM_RBUTTONDOWN, onContextMenu)
	// CDM EXTENSION BEGINS (fulDC)
	ALT_MSG_MAP(FILTER_MESSAGE_MAP)
		MESSAGE_HANDLER(WM_KEYUP, onFilterChar)
		COMMAND_CODE_HANDLER(CBN_SELCHANGE, onSelChange)
	// CDM EXTENSION ENDS
	// pothead extension starts svn50
	ALT_MSG_MAP(CLEAR_MESSAGE_MAP)
		COMMAND_ID_HANDLER(IDC_CLEAR, onClear)
	// pothead extension ends
	//Sulan start svn64
		COMMAND_ID_HANDLER(IDC_LOG, onOpenHubLog)
	//End
	END_MSG_MAP()

	virtual void OnFinalMessage(HWND /*hWnd*/) {
		dcassert(frames.find(server) != frames.end());
		dcassert(frames[server] == this);
		frames.erase(server);
		delete this;
	}

	LRESULT onSpeaker(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/);
	LRESULT onMultiCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onSizeMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT onClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onDoubleClickUsers(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/);
	LRESULT onTabContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/);
	LRESULT onChar(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onShowUsers(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onFollow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onLButton(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onEnterUsers(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/);
	LRESULT onURL(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
	LRESULT onGetToolTip(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/);
	// CDM EXTENSION BEGINS (fulDC)
	LRESULT onFilterChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	LRESULT onSelChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	// CDM EXTENSION ENDS
	// pothead extension starts
	LRESULT onClear(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onOpenHubLog(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onCopyHubAddy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	// pothead extension ends
	// R2 extension begins svn142
	LRESULT onResolvedIP(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	// R2 extension ends svn142
	//Sulan start 144
	LRESULT onStartChecking(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		if(!client->getOp()) {
			addClientLine(STRING(OP_ONLY));
		} else if(client->startChecking()) {
			addClientLine(CSTRING(CHECKING_STARTED));
		} else {
			client->stopChecking();
			addClientLine(CTSTRING(CHECKING_STOPPED));
		}
		return 0;
	}
	//End
	void UpdateLayout(BOOL bResizeBars = TRUE);
	void addLine(const tstring& aLine);
	void addClientLine(const tstring& aLine, bool inChat = true);
	void onEnter();
	void onTab();
	void runUserCommand(::UserCommand& uc);

	static void openWindow(const tstring& server, const string& nick = Util::emptyString, const string& password = Util::emptyString, const string& description = Util::emptyString
		// CDM EXTENSION BEGINS FAVS
		//Add to favs
		, const string& rawOne = Util::emptyString
		, const string& rawTwo = Util::emptyString
		, const string& rawThree = Util::emptyString
		, const string& rawFour = Util::emptyString
		, const string& rawFive = Util::emptyString
		, const string& rawSix = Util::emptyString
		, const string& rawSeven = Util::emptyString
		, const string& rawEight = Util::emptyString
		, const string& rawNine = Util::emptyString
		, const string& rawTen = Util::emptyString
		, const string& opChat = Util::emptyString
		// pothead extension starts #9 svn 34
		//, bool userIp = false
		, bool userIp = BOOLSETTING(SEND_USERIP_ON_CONNECT)
		// pothead extension ends
		, bool checkClients = false
		, bool checkFilelists = false
		, bool checkFakeShare = false
		, bool checkOnConnect = false
		//Gabberworld start
		, const string& countryCodeCheck = Util::emptyString
		, int countryCodeRaw = 0
		//Sulan start
		, const string& protectedUsers = Util::emptyString
		, bool hideShare = false
		//Sulan start 28
		, const string& trigger = Util::emptyString
		//Sulan start svn86
		, bool logChat = true
		//Sulan start svn101
		, string sColumnOrder = Util::emptyString
		, string sColumnWidth = Util::emptyString
		, string sColumnVisible = Util::emptyString
		//Sulan start svn124
		, int windowposx = 0
		, int windowposy = 0
		, int windowsizex = 0
		, int windowsizey = 0
		, int windowtype = 0
		//End
		// pothead starts
		, const string& hubMessage = Util::emptyString
		, bool useMyinfoDetect = false
		, const string& regStatus = Util::emptyString
		, const string& disableRaws = "0;0;0;0;0;0;0;0;0;0"
		// pothead ends
		// CDM EXTENSION ENDS
		);
	static void closeDisconnected();
	static void reconnectDisconnected();
	// CDM EXTENSION BEGINS
	LRESULT onCheckHubCounts(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onMultiHubKick(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
// R2 extension begins svn143
	LRESULT onIpLookup(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
// R2 extension ends svn143
	LRESULT onRipeLookup(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		int sel = -1;
		while((sel = ctrlUsers.GetNextItem(sel, LVNI_SELECTED)) != -1) {
			UserInfo* u = (UserInfo*) ctrlUsers.GetItemData(sel);
			string ip = u->user->getHisIp();
			if(!ip.empty()) {
				WinUtil::openLink("http://www.ripe.net/perl/whois?form_type=simple&full_query_string=&searchtext=" + ip + "&do_search=Search");
			}
			break;
		}
		return 0;
	}

	LRESULT onHublistLookup(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		int sel = -1;
		while((sel = ctrlUsers.GetNextItem(sel, LVNI_SELECTED)) != -1) {
			UserInfo* u = (UserInfo*) ctrlUsers.GetItemData(sel);
			WinUtil::openLink("http://www.hublist.org/?p=search&mode=users&nick=" + u->user->getNick() + "&when=&country=");
			break;
		}
		return 0;
	}

	LRESULT onGetUserResponses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		getUserResponses(QueueManager::M_NICK);
		return 0;
	}

	LRESULT onGetoNickUserResponses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		getUserResponses(QueueManager::O_NICK);
		return 0;
	}

	LRESULT onGetrNickUserResponses(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		getUserResponses(QueueManager::R_NICK);
		return 0;
	}

	LRESULT onCheckFileList(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		checkFileList();
		return 0;
	}

	LRESULT onGetCheckFileList(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		int i=-1;
		if(client->isConnected()) {
			while( (i = ctrlUsers.GetNextItem(i, LVNI_SELECTED)) != -1) {
				try {
				QueueManager::getInstance()->addList(((UserInfo*)ctrlUsers.GetItemData(i))->user, QueueItem::FLAG_CLIENT_VIEW);
				} catch(const Exception&) {
				}
			}
		}
	
		checkFileList();
		return 0;
	}

	LRESULT onReport(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		int i=-1;
		if(client->isConnected()) {
			while( (i = ctrlUsers.GetNextItem(i, LVNI_SELECTED)) != -1) {
				doReport(((UserInfo*)ctrlUsers.GetItemData(i))->user);
			}
		}
		return 0;
	}

	LRESULT onCleanUser(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onWinampSpam(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		tstring cmd, param, message, status;
		cmd = _T("/winamp");
		if(WinUtil::checkCommand(cmd, param, message, status)){
			if(!message.empty()) {
				client->sendMessage(message);
			}
			if(!status.empty()) {
				addClientLine(status);
			}
		}
		return 0;
	}
	LRESULT onSwitch(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		m_bVertical = !m_bVertical;
		if(m_bVertical) {
			SetSplitterPanes(ctrlClient.m_hWnd, ctrlUsers.m_hWnd, false);
			horPos = m_nProportionalPos;
			m_nProportionalPos = verPos;
		} else {
			SetSplitterPanes(ctrlUsers.m_hWnd, ctrlClient.m_hWnd, false);
			verPos = m_nProportionalPos;
			m_nProportionalPos = horPos;
		}
		UpdateLayout();
		return 0;
	}
	LRESULT onCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled);

	void doReport(User::Ptr& u);
	void getUserResponses(int type = 0);
	void checkFileList();

	// CDM EXTENSION ENDS
	// pothead extension starts #3 and svn62
	LRESULT onMultiHubRaw(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onMainBan(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	// pothead extension ends
	LRESULT onSetFocus(UINT /* uMsg */, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);

	LRESULT onSendMessage(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		onEnter();
		return 0;
	}
	
	LRESULT onAddAsFavorite(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		addAsFavorite();
		return 0;
	}

	LRESULT onCloseWindow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		PostMessage(WM_CLOSE);
		return 0;
	}

	LRESULT onCtlColor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) {
		HWND hWnd = (HWND)lParam;
		HDC hDC = (HDC)wParam;
		if(hWnd == ctrlClient.m_hWnd || hWnd == ctrlMessage.m_hWnd
			// CDM EXTENSION BEGINS (fulDC)
			|| hWnd == ctrlFilter.m_hWnd || ctrlFilterSel.m_hWnd
			// CDM EXTENSION ENDS
			) {
			::SetBkColor(hDC, WinUtil::bgColor);
			::SetTextColor(hDC, WinUtil::textColor);
			return (LRESULT)WinUtil::bgBrush;
		} else {
			return 0;
		}
	}

	LRESULT onRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		if(client->isConnected()) {
			clearUserList();
			client->refreshUserList();
		}
		return 0;
	}
	
	LRESULT onEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		ctrlClient.Copy();
		return 0;
	}

	LRESULT onEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		findDlg.Create(TRUE, _T(""));
		findDlg.ShowWindow(TRUE);
		return 0;
	}

	LRESULT OnFileReconnect(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		reconnect();
		return 0;
	}

	LRESULT onKeyDownUsers(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) {
		NMLVKEYDOWN* l = (NMLVKEYDOWN*)pnmh;
		if(l->wVKey == VK_TAB) {
			onTab();
		}
		return 0;
	}

	static DWORD CALLBACK funWithWin32CallBacks(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb);

	void reconnect() {
		clearUserList();
		client->addListener(this);
		client->connect(server);
	}

private:
	class UserInfo;
public:
	TypedListViewCtrl<UserInfo, IDC_USERS>& getUserList() { return ctrlUsers; }
private:
	// pothead extension starts (r2 code) svn62
	string sMarkedText;
	// pothead extension ends

	enum Speakers { UPDATE_USER, UPDATE_USERS, REMOVE_USER, ADD_CHAT_LINE,
		ADD_STATUS_LINE, ADD_SILENT_STATUS_LINE, SET_WINDOW_TITLE, GET_PASSWORD, 
		PRIVATE_MESSAGE, STATS, CONNECTED, DISCONNECTED, ATTENTION, REMOVE_LINE
	};

	enum {
		//IMAGE_USER = 0, IMAGE_OP
		IMAGE_USER = 0, IMAGE_OP, IMAGE_MODEM, IMAGE_ISDN, IMAGE_SATELLITE, IMAGE_DSL, IMAGE_CABLE, IMAGE_LAN, IMAGE_SERVER, IMAGE_FIREBALL, IMAGE_UNKNOWN
	};
	
	enum {
		COLUMN_FIRST, 
		COLUMN_NICK = COLUMN_FIRST, 
		COLUMN_SHARED, 
		COLUMN_IP,
		COLUMN_DESCRIPTION, 
		COLUMN_TAG,
		COLUMN_CONNECTION, 
		COLUMN_PK,
		COLUMN_EMAIL, 
		// CDM EXTENSION BEGINS
		COLUMN_HOST, 
		COLUMN_BYTES_SHARED, 
		COLUMN_SUPPORTS, 
		COLUMN_CLIENT, 
		COLUMN_FILELIST_SIZE, 
		COLUMN_LOCK, 
		COLUMN_STATUS, 
		COLUMN_DOWNSPEED,
		COLUMN_USER_IP,
		COLUMN_CHEATING_DESCRIPTION,
		COLUMN_ISP,
		COLUMN_FILELIST_GEN,
		COLUMN_PERCENT_HASHED,
		//Sulan fix
		COLUMN_COMMENT,
		//Sulan start svn94
		COLUMN_MYINFOS,
		//Sulan start svn101
		COLUMN_LISTLEN,
		COLUMN_CID,
		//End
		//End
		// http://www.imperialnet.org/forum/viewtopic.php?t=1313
		//Sulan start svn171
		COLUMN_HUBS,
		// End
		// pothead starts svn195
		COLUMN_SLOTS,
		COLUMN_LIMIT,
		// pothead ends
		COLUMN_COUNTRY,
		// CDM EXTENSION ENDS
		COLUMN_LAST
	};
	friend struct CompareItems;
	class UserInfo : public UserInfoBase, public FastAlloc<UserInfo> {
	public:
		UserInfo(const User::Ptr& u) : UserInfoBase(u), op(false) { 
			update(); 
		}

		const tstring& getText(int col) const {
			return columns[col];
		}

		static int compareItems(const UserInfo* a, const UserInfo* b, int col) {
			// CDM EXTENSION BEGINS (fulDC)
			if(a == NULL || b == NULL){
				dcdebug("UserInfo::compareItems: pointer == NULL\n");
				return 0;
			}
			// CDM EXTENSION ENDS
			switch(col) {
				case COLUMN_NICK:
					if(a->getOp() && !b->getOp()) {
						return -1;
					} else if(!a->getOp() && b->getOp()) {
						return 1;
					}
					return Util::stricmp(a->user->getNick(), b->user->getNick());	
				case COLUMN_SHARED:	return compare(a->user->getBytesShared(), b->user->getBytesShared());
				case COLUMN_IP: return Util::stricmp(a->user->getIp(), b->user->getIp());
				case COLUMN_DESCRIPTION: return Util::stricmp(a->user->getDescription(), b->user->getDescription());
				case COLUMN_TAG: return Util::stricmp(a->user->getTag(), b->user->getTag());
				case COLUMN_CONNECTION: return Util::stricmp(a->user->getConnection(), b->user->getConnection());
				case COLUMN_PK: return Util::stricmp(a->user->getPk(), b->user->getPk());
				case COLUMN_EMAIL: return Util::stricmp(a->user->getEmail(), b->user->getEmail());
				// CDM EXTENSION BEGINS
				case COLUMN_HOST: return Util::stricmp(a->user->getHost(), b->user->getHost());
				case COLUMN_BYTES_SHARED: return compare(a->user->getBytesShared(), b->user->getBytesShared());
				case COLUMN_SUPPORTS: return Util::stricmp(a->user->getSupports(), b->user->getSupports());
				case COLUMN_CLIENT: return Util::stricmp(a->user->getClientType(), b->user->getClientType());
				case COLUMN_FILELIST_SIZE: return compare(a->user->getFileListSize(), b->user->getFileListSize());
				case COLUMN_LOCK: return Util::stricmp(a->user->getLock(), b->user->getLock());
				case COLUMN_STATUS: return compare(a->user->getIconStatus(), b->user->getIconStatus());
				case COLUMN_DOWNSPEED: return compare(a->user->getDownloadSpeed(), b->user->getDownloadSpeed());
				case COLUMN_USER_IP: return Util::stricmp(a->user->getUserIp(), b->user->getUserIp());
				case COLUMN_CHEATING_DESCRIPTION: return Util::stricmp(a->user->getCheatingString(), b->user->getCheatingString());
				case COLUMN_ISP: return Util::stricmp(a->user->getIsp(), b->user->getIsp());
				case COLUMN_FILELIST_GEN: return Util::stricmp(a->user->getFilelistGenerator(), b->user->getFilelistGenerator());
				case COLUMN_PERCENT_HASHED: return Util::stricmp(a->user->getPercentHashed(), b->user->getPercentHashed());
				//Sulan fix
				case COLUMN_COMMENT: return Util::stricmp(a->user->getClientComment(), b->user->getClientComment());
				//Sulan start svn94
				case COLUMN_MYINFOS: return compare(a->user->getMyinfos(), b->user->getMyinfos());
				//Sulan start svn99
				case COLUMN_LISTLEN: return compare(a->user->getListLength(), b->user->getListLength());
				case COLUMN_CID: return Util::stricmp(a->user->getCid(), b->user->getCid());
				//Sulan start svn171
				case COLUMN_HUBS: return compare(a->intHubs, b->intHubs);
				// pothead starts svn195
				case COLUMN_SLOTS: return compare(a->intSlots, b->intSlots);
				case COLUMN_LIMIT: return compare(a->intLimitSpeed, b->intLimitSpeed);
				// pothead ends
				case COLUMN_COUNTRY: return compare(a->user->getCountryCode(), b->user->getCountryCode());
				//End
				// http://www.imperialnet.org/forum/viewtopic.php?t=1313
				// CDM EXTENSION ENDS
				default: return 0;
			}
		}

		void update() { 
			if(user->getMyinfos() > 0 && (GET_TICK() - user->getLoggedIn())>0 ){
				myinfos = "[ " + Util::toString(user->getMyinfos()) + " ] interval: [ " + Util::formatSeconds(((GET_TICK() - user->getLoggedIn())/1000) / user->getMyinfos()) + " ]";
			}else{
				myinfos = "[ 0 ] interval: [ 0 ]";
			}
			status = Util::formatStatus(user->getIconStatus());
			intHubs = user->getTotalHubsAsInt();
			intSlots = Util::toInt(user->getTagSlots());
			intLimitSpeed = Util::toInt(user->getLimitSpeed());										//we fill be back here :P
			
			columns[COLUMN_NICK]				 =	(user->getNick());
			columns[COLUMN_SHARED]				 =	(Util::formatBytes(user->getBytesShared()));
			columns[COLUMN_DESCRIPTION]			 =	(user->getDescription());
			columns[COLUMN_TAG]					 =	(user->getTag());
			columns[COLUMN_CONNECTION]			 =	(user->getConnection());
			columns[COLUMN_EMAIL]				 =	(user->getEmail());
			columns[COLUMN_IP]					 =	(user->getIp());
			columns[COLUMN_PK]					 =	(user->getPk());
			columns[COLUMN_HOST]				 =	(user->getHost());
			columns[COLUMN_BYTES_SHARED]		 =	(Util::toString(user->getBytesShared()) + " B");
			columns[COLUMN_SUPPORTS]			 =	(user->getSupports());
			columns[COLUMN_CLIENT]				 =	(user->getClientType());
			columns[COLUMN_FILELIST_SIZE]		 =	(Util::formatBytes(user->getFileListSize()));
			columns[COLUMN_LOCK]				 =	(user->getLock());
			columns[COLUMN_STATUS]				 =	(status);
			columns[COLUMN_DOWNSPEED]			 =	(Util::formatBytes(user->getDownloadSpeed()) + "/s");
			columns[COLUMN_USER_IP]				 =	(user->getUserIp());
			columns[COLUMN_CHEATING_DESCRIPTION] =	(user->getCheatingString());
			columns[COLUMN_ISP]					 =	(user->getIsp());
			columns[COLUMN_FILELIST_GEN]		 =	(user->getFilelistGenerator());
			columns[COLUMN_PERCENT_HASHED]		 =	(user->getPercentHashed());
			columns[COLUMN_COMMENT]				 =	(user->getClientComment());
			columns[COLUMN_MYINFOS]				 =	(myinfos);
			columns[COLUMN_LISTLEN]				 =	(Util::formatBytes(user->getListLength()) + " (" + Util::toString(user->getListLength()) + " B)");
			columns[COLUMN_CID]					 =	(user->getCid());
			columns[COLUMN_HUBS]				 =	(user->getTotalHubs() + " (" + user->getNormalHubs() + "/" + user->getRegisteredHubs() + "/" + user->getOpHubs() + ")");
			columns[COLUMN_SLOTS]				 =	(user->getTagSlots());
			columns[COLUMN_LIMIT]				 =	(user->getLimitSpeed());
			columns[COLUMN_COUNTRY]				 =	(user->getCountryCode());
			op = user->isSet(User::OP); 
		}

		tstring columns[COLUMN_LAST];
		GETSET(string, myinfos, Myinfos);
		GETSET(string, status, Status);
		GETSET(int, intHubs, IntHubs);
		GETSET(int, intSlots, IntSlots);
		GETSET(int, intLimitSpeed, IntLimitSpeed);
		GETSET(bool, op, Op);
		
		//Sulan start svn101
		int imageIndex() {
			return /*WinUtil::*/getImage(user);
		}
		//End
	};

	class PMInfo {
	public:
		PMInfo(const User::Ptr& u, const string& m) : user(u), msg(m) { };
		User::Ptr user;
		string msg;
	};

	HubFrame(const string& aServer, const string& aNick, const string& aPassword, const string& aDescription
		// CDM EXTENSION BEGINS FAVS
		//Add to favs
		, const string& aRawOne
		, const string& aRawTwo
		, const string& aRawThree
		, const string& aRawFour
		, const string& aRawFive
		, const string& aRawSix
		, const string& aRawSeven
		, const string& aRawEight
		, const string& aRawNine
		, const string& aRawTen
		, const string& aOpChat
		, bool aUserIp
		, bool aCheckClients
		, bool aCheckFilelists
		, bool aCheckFakeShare
		, bool aCheckOnConnect
		//Gabberworld start
		, const string& aCountryCodeCheck
		, int aCountryCodeRaw
		//Sulan start
		, const string& aProtectedUsers
		, bool aHideShare
		//Sulan start 28
		, const string& aTrigger
		//Sulan start svn86
		, bool aLogChat
		//Sulan start svn101
		, string scolumnorder
		, string scolumnwidth
		, string scolumnvisible
		//Sulan start svn124
		, int /*windowposx*/
		, int /*windowposy*/
		, int /*windowsizex*/
		, int /*windowsizey*/
		, int /*windowtype*/
		//End
		// pothead starts svn192 svn196 (sulan code)
		, const string& aHubMessage
		, bool aUseMyinfoDetect
		, const string& aRegStatus
		, const string& aDisableRaws
		// pothead ends
		// CDM EXTENSION ENDS
		) : 
	waitingForPW(false), extraSort(false), server(aServer), closed(false), 
		updateUsers(false), curCommandPosition(0), rememberAutoscroll(false),
		ctrlMessageContainer(_T("edit"), this, EDIT_MESSAGE_MAP),
		showUsersContainer(_T("BUTTON"), this, EDIT_MESSAGE_MAP),
		clientContainer(_T("edit"), this, EDIT_MESSAGE_MAP)
		// CDM EXTENSION BEGINS (fulDC)
		,
		ctrlFilterContainer(_T("edit"), this, FILTER_MESSAGE_MAP),
		ctrlFilterSelContainer(_T("COMBOBOX"), this, FILTER_MESSAGE_MAP)
		// CDM EXTENSION ENDS
		// pothead extension starts #13 svn50
		, 
		clearContainer(_T("BUTTON"), this, CLEAR_MESSAGE_MAP),
		statusContainer(STATUSCLASSNAME, this, CLEAR_MESSAGE_MAP)
		//Sulan start svn64
		, logContainer(_T("BUTTON"), this, CLEAR_MESSAGE_MAP)
		//Sulan start svn101
		, sColumnOrder(scolumnorder)
		, sColumnWidth(scolumnwidth)
		, sColumnVisible(scolumnvisible)
		//End
		// pothead extension ends

	{
		client = ClientManager::getInstance()->getClient();
		client->setMe(ClientManager::getInstance()->getUser(SETTING(NICK), client, false));
		client->setUserInfo(BOOLSETTING(GET_USER_INFO));
		client->setNick(aNick.empty() ? SETTING(NICK) : aNick);
			
		if (!aDescription.empty())
		client->setDescription(aDescription);
		client->setPassword(aPassword);
		// CDM EXTENSION BEGINS FAVS
		//Add to favs
		client->setRawOne(aRawOne);
		client->setRawTwo(aRawTwo);
		client->setRawThree(aRawThree);
		client->setRawFour(aRawFour);
		client->setRawFive(aRawFive);
		client->setRawSix(aRawSix);
		client->setRawSeven(aRawSeven);
		client->setRawEight(aRawEight);
		client->setRawNine(aRawNine);
		client->setRawTen(aRawTen);
		client->setOpChat(aOpChat);
		client->setSendUserIp(aUserIp);
		client->setCheckClients(aCheckClients);
		client->setCheckFilelists(aCheckFilelists);
		client->setCheckFakeShare(aCheckFakeShare);
		client->setCheckOnConnect(aCheckOnConnect);
		//Gabberworld start
		client->setCountryCodeCheck(aCountryCodeCheck);
		client->setCountryCodeRaw(aCountryCodeRaw);
		//Sulan start
		client->setProtectedUsers(aProtectedUsers);
		client->setHideShare(aHideShare);
		//Sulan start 28
		client->setTrigger(aTrigger);
		//Sulan start sv86
		client->setLogChat(aLogChat);
		//End
		// pothead starts svn192 svn196 (sulan code)
		client->setUseMyinfoDetect(aUseMyinfoDetect);
		client->setHubMessage(aHubMessage);
		client->setRegStatus(aRegStatus);
		client->setDisableRaws(aDisableRaws);
		// pothead ends
		// CDM EXTENSION ENDS

		client->addListener(this);
		TimerManager::getInstance()->addListener(this);
		timeStamps = BOOLSETTING(TIME_STAMPS);
		//Sulan start svn 44
		ClientVersionManager::getInstance()->addListener(this);
		//End

// R2 extension begins svn142
		resolveBuffer = NULL;
// R2 extension ends svn142
	}

	~HubFrame() {
		ClientManager::getInstance()->putClient(client);
		//Sulan start svn 44
		ClientVersionManager::getInstance()->removeListener(this);
		//End

// R2 extension begins svn142
		if(resolveBuffer)
			delete[] resolveBuffer;
// R2 extension ends svn142
	}

	typedef HASH_MAP<tstring, HubFrame*> FrameMap;
	typedef FrameMap::iterator FrameIter;
	static FrameMap frames;

	tstring redirect;
	bool timeStamps;
	bool showJoins;
	bool favShowJoins;
	tstring complete;

	string lastKick;
	string lastRedir;
	string lastServer;
	
	bool waitingForPW;
	bool extraSort;

	StringList prevCommands;
	tstring currentCommand;
	StringList::size_type curCommandPosition;		//can't use an iterator because StringList is a vector, and vector iterators become invalid after resizing

	string currentChatMessage;			//needed by richedit callback.

	bool rememberAutoscroll;	// remember if scrollbar was at bottom

	CFindReplaceDialog findDlg;

	Client* client;
	tstring server;
	CContainedWindow ctrlMessageContainer;
	CContainedWindow clientContainer;
	CContainedWindow showUsersContainer;
	// CDM EXTENSION BEGINS (fulDC)
//	typedef HASH_MAP<User::Ptr, UserInfo*, User::HashFunction> UserMap;
//	typedef UserMap::iterator UserMapIter;
//	UserMap userMap;

	CContainedWindow ctrlFilterContainer;
	CContainedWindow ctrlFilterSelContainer;
	string filter;
	//typedef list< UserInfo* > FilterList;
	typedef multimap< string, UserInfo* > UserMap;
	typedef pair< string, UserInfo* > UserPair;
	UserMap usermap; //save all userinfo items that don't match the filter here
	CEdit ctrlFilter;
	CComboBox ctrlFilterSel;
	// pothead extension starts #13 svn50
	CButton ctrlClear;
	CContainedWindow clearContainer, statusContainer;
	// pothead extension ends
	//Sulan start svn64
	CButton ctrlLog;
	CContainedWindow logContainer;
	//End


	void removeUser(const User::Ptr& u);
	void updateUserList();

	void clearUserList();
	int verPos, horPos;
	// CDM EXTENSION ENDS

	CMenu userMenu;
	CMenu tabMenu;
	CMenu grantMenu;
	CMenu editMenu;
	//Sulan start 144
	CMenu copyMenu;
	//End

	CButton ctrlShowUsers;
	CRichEditCtrl ctrlClient;
	
	CEdit ctrlMessage;
	typedef TypedListViewCtrl<UserInfo, IDC_USERS> CtrlUsers;
	CtrlUsers ctrlUsers;
	CStatusBarCtrl ctrlStatus;

	bool closed;

	StringMap ucParams;
	StringMap tabParams;
	bool tabMenuShown;

	typedef vector<pair<User::Ptr, Speakers> > UpdateList;
	typedef UpdateList::iterator UpdateIter;

	UpdateList updateList;
	CriticalSection updateCS;
	bool updateUsers;

	enum { MAX_CLIENT_LINES = 5 };
	StringList lastLinesList;
	string lastLines;
	CToolTipCtrl ctrlLastLines;
	
	static int columnIndexes[COLUMN_LAST];
	static int columnSizes[COLUMN_LAST];
	
// R2 extension begins svn142
	char *resolveBuffer;
	bool isIP;
// R2 extension ends svn142

	int findUser(const User::Ptr& aUser);

	bool updateUser(const User::Ptr& u);

	void addAsFavorite();

	//Sulan start svn101
	static int getImage(const User::Ptr& u) {
	//End
		if(SETTING(USER_LIST_IMAGES) < 2) {
			int image = u->isSet(User::OP) ? IMAGE_OP : IMAGE_USER;
			
			if(u->isSet(User::DCPLUSPLUS))
				image+=2;
			if(u->isSet(User::PASSIVE)||u->getTag().find("M:P")!=string::npos) {
				image+=4;
			}
			return image;	
		} else {
			int image = IMAGE_UNKNOWN;
			const string& tmp = u->getConnection();
			int status = u->getIconStatus();
			if (u->isSet(User::OP)) {
				image = IMAGE_OP;
			} else if( (status == 4) || (status == 5) || (status == 6) || (status == 7) ) {
				image = IMAGE_SERVER;
			} else if( (status == 8) || (status == 9) || (status == 10) || (status == 11) ) {
				image = IMAGE_FIREBALL;
			} else if( (tmp == "28.8Kbps") ||
				(tmp == "33.6Kbps") ||
				(tmp == "56Kbps") ||
				(tmp == "Modem") ) {
				image = IMAGE_MODEM;
			} else if(tmp == "ISDN") {
				image = IMAGE_ISDN;
			} else if( (tmp == "Satellite") ||
				(tmp == "Wireless") ||
				(tmp == "Microwave") ) {
				image = IMAGE_SATELLITE;
			} else if(tmp == "DSL") {
				image = IMAGE_DSL;
			} else if(tmp == "Cable") {
				image = IMAGE_CABLE;
			} else if( (tmp == "LAN(T1)") ||
				(tmp == "LAN(T3)") ) {
				image = IMAGE_LAN;
			}
			if( (status == 2) || (status == 3) || (status == 6) || (status == 7) || (status == 10) || (status == 11) ) {
				image+=10;
			}
			if(u->isSet(User::DCPLUSPLUS)) {
				image+=20;
			}
			if(u->isSet(User::PASSIVE)) {
				image+=40;
			}
			return image - 1;	
		}
	}

	void updateStatusBar() {
		if(m_hWnd)
			PostMessage(WM_SPEAKER, STATS);
	}

	bool scrollbarAtBottom();

	void startFlashing();
	void stopFlashing();

	// TimerManagerListener
	virtual void on(TimerManagerListener::Second, DWORD /*aTick*/) throw();

	// ClientListener
	virtual void on(Connecting, Client*) throw();
	virtual void on(Connected, Client*) throw();
	virtual void on(BadPassword, Client*) throw();
	virtual void on(UserUpdated, Client*, const User::Ptr&) throw();
	virtual void on(UsersUpdated, Client*, const User::List&) throw();
	virtual void on(Redirect, Client*, const string&) throw();
	virtual void on(Failed, Client*, const string&) throw();
	virtual void on(GetPassword, Client*) throw();
	virtual void on(HubName, Client*) throw();
	virtual void on(Message, Client*, const string&) throw();
	virtual void on(PrivateMessage, Client*, const User::Ptr&, const string&) throw() ;
	virtual void on(NickTaken, Client*) throw();
	virtual void on(SearchFlood, Client*, const string&) throw();
	virtual void on(UserIp, Client*, const StringList&) throw();
	virtual void on(Quit, Client*, const User::Ptr&) throw();
	virtual void on(Attention, Client*) throw();

	void speak(Speakers s) { PostMessage(WM_SPEAKER, (WPARAM)s); };
	void speak(Speakers s, const string& msg) { PostMessage(WM_SPEAKER, (WPARAM)s, (LPARAM)new string(msg)); };
	void speak(Speakers s, const User::Ptr& u) { 
		Lock l(updateCS);
		updateList.push_back(make_pair(u, s));
		updateUsers = true;
	};
	void speak(Speakers s, const User::Ptr& u, const string& line) { PostMessage(WM_SPEAKER, (WPARAM)s, (LPARAM)new PMInfo(u, line)); };
	//Sulan start svn 44
	//VersionManagerListener
	virtual void on(VersionManagerListener::Types type, const string& aName, const string& aVersion, const string& aAddy, const string& aMessage) throw();
	//Sulan start svn97 (fix 94)
	int cur_col;
	//Sulan start svn101
	bool ShowUserList;
	string sColumnOrder;
	string sColumnWidth;
	string sColumnVisible;
	//Sulan start old svn124, gabberworld update
	virtual void on(SettingsManagerListener::Save, SimpleXML*) throw();
	//End

// R2 extension begins svn142
	bool resolve(const string& aDns);
// R2 extension ends svn142
//gabberworld starts
public:
	static void onClearAllMainChat();
	static void onStopCheckingAll();
	static void onStartCheckingAll();
	static void onCloseAllHub();
//gabberworld ends
};
/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM_H__A7078724_FD85_4F39_8463_5A08A5F45E33__INCLUDED_)

/**
 * @file
 * $Id: HubFrame.h 332 2005-09-03 17:09:28Z Pothead $
 */